/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package action;

import action.administration.BidItem;
import action.administration.KPItem;
import action.administration.MarkovItem;
import au.com.bytecode.opencsv.CSVReader;
import static com.opensymphony.xwork2.Action.SUCCESS;
import com.opensymphony.xwork2.ActionSupport;
import database.BidhistoryDAO;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import model.MDPModel;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.Result;
import org.apache.struts2.interceptor.validation.SkipValidation;

/**
 *
 * @author Trang
 */
@Namespace("/Administration/Bidding")
public class MarkovAction extends ActionSupport {

    private File inputFile;
    private String inputFileContentType;
    private String inputFileFileName;
    private List<BidItem> bidItems = new ArrayList<BidItem>();
    private  List<MarkovItem> markovItem = new ArrayList<MarkovItem>();
    BidhistoryDAO bidDAO = new BidhistoryDAO();
    private String output;
    private String numberskey;
    private String budgetUser;

    public String getNumberskey() {
        return numberskey;
    }

    public void setNumberskey(String numberskey) {
        this.numberskey = numberskey;
    }

    public String getBudgetUser() {
        return budgetUser;
    }

    public void setBudgetUser(String budgetUser) {
        this.budgetUser = budgetUser;
    }    

    public MarkovAction() {
    }

    public File getInputFile() {
        return inputFile;
    }

    public String getInputFileContentType() {
        return inputFileContentType;
    }

    public void setInputFileContentType(String inputFileContentType) {
        this.inputFileContentType = inputFileContentType;
    }

    public String getInputFileFileName() {
        return inputFileFileName;
    }

    public void setInputFileFileName(String inputFileFileName) {
        this.inputFileFileName = inputFileFileName;
    }

    public void setInputFile(File inputFile) {
        this.inputFile = inputFile;
    }

    public List<BidItem> getBidItems() {
        return bidItems;
    }

    public void setBidItems(List<BidItem> bidItems) {
        this.bidItems = bidItems;
    }

    public String getOutput() {
        return output;
    }

    public void setOutput(String output) {
        this.output = output;
    }

    @Override
    public String execute() throws Exception {
        return SUCCESS;
    }

    @Override
    public void validate() {
        if (this.inputFile != null) {
            if (!this.inputFileContentType.equals("application/vnd.ms-excel")) {
                addFieldError("inputFile", ".csv is required.");
            }

            double length = this.inputFile.length();
            if (length / 1024 / 1024 / 1024 <= 0.001) {
            } else {
                addFieldError("inputFile", "The file is too large (>1024KB).");
            }
        } else {
            addFieldError("inputFile", "A .csv file is required.");
        }
        if(Integer.parseInt(this.numberskey) < 0)
            addFieldError("numberskey", "Number of suggession key must large than 0");
        if(Double.parseDouble(this.budgetUser) < 0)
            addFieldError("budgetUser", "Budget per user must large than 0");
    }

    @Action(value = "MarkovUpload", results = {
        @Result(name = "success", location = "/w_uploadCSV.jsp")
    })
    @SkipValidation
    public String upload() {
        return SUCCESS;
    }

    @Action(value = "MarkovResult", results = {
        @Result(name = "success", location = "/w_markovResult.jsp"),
        @Result(name = "input", location = "/w_uploadCSV.jsp")
    })
    public String process() throws IOException {
        CSVReader reader = new CSVReader(new FileReader(inputFile));

        String[] nextLine;

        //headers - ignore first line
        if ((nextLine = reader.readNext()) != null) {
            // nextLine[] is an array of values from the line
            for (String s : nextLine) {
                System.out.print(s + " - ");
            }
            System.out.println("\n");
        }

        int i = 0;
        List<KPItem> kpitems = new ArrayList<KPItem>();
        //assume revenue for each product = $100, budget = $5000
        double revenue = 100;
        double budget = 5000;
        bidDAO.DeleteBidHistoty();
        while ((nextLine = reader.readNext()) != null) {

            String s1 = nextLine[0];
            String s2 = nextLine[1];
            String s3 = nextLine[2];
            String s4 = nextLine[3];
            String s5 = nextLine[4];
            String s6 = nextLine[5];
            String s7 = nextLine[6];
            String s8 = nextLine[7];
            String s9 = nextLine[8];
            String s10 = nextLine[9];

            //get sample data
            if (i < 10) {
                SimpleDateFormat sdf = new SimpleDateFormat("mm/dd/yy");
                Date idate = new Date();
                try {
                    idate = sdf.parse(s1);
                } catch (ParseException ex) {
                    Logger.getLogger(action.administration.KPAction.class.getName()).log(Level.SEVERE, null, ex);
                }

                String ikeyword = s2;

                int iqualityscore = Integer.parseInt(s3);

                String scpc = s4.substring(1, 5);
                double icpc = Double.parseDouble(scpc);

                int iimpressions = Integer.parseInt(s5);

                int iclicks = Integer.parseInt(s6);

                double ictr = Double.parseDouble(s7.substring(0, 4));

                double iavgCpc = Double.parseDouble(s8.substring(1, 5));

                double icost = Double.parseDouble(s9.substring(1, 5));

                double iavgPosition = Double.parseDouble(s10);
                
                double notConvert = 1 - iclicks/iimpressions;
                BidItem bi = new BidItem(notConvert, idate, ikeyword, iqualityscore, icpc, iimpressions, iclicks, ictr, iavgCpc, icost, iavgPosition);
                
                System.out.println("Trang2");
                
                bidDAO.addBid(bi);
                System.out.println("Trang");
                
                System.out.println(bi.toString());

                bidItems.add(bi);
            }
        }
            int numberOfKey = Integer.parseInt(numberskey);
            double budgetPerUser = Double.parseDouble(budgetUser);
            List<MDPModel> models = new ArrayList<MDPModel>();
            models = bidDAO.getAllModel();
            int count = 0;
            //size = nukber of key + 3 (for 3 specific state)
            int size = models.size() + 3;
            
            int size2 = models.size();
            System.out.println("model size"+ size2);
            double conversionRate = 0.05;
            int j = 0, l = 0;
            double a[][]= new double[size][size];
            double []Pxa1xn = new double [models.size()];
            
            for(MDPModel item: models)
            {
                Pxa1xn[l] = (item.getPxab())* conversionRate;
                l++;
            }
            //System.out.println("1");
            for(MDPModel item: models)
            {
                //create Pxab - probability from specific state to begin state
                a[j][size - 3] = item.getPxab();
                j++;
            }
            int click[] = new int[models.size()];
            
            int index1= 0, index2=0;
            //get total click of each item
            //System.out.println("2");
            for(MDPModel item1: models)
            {
                click[index1] = item1.getTotalClick();
                index1++;
            }
            double [] conversionBetween = new double[models.size()];
            //System.out.println("3");
            for(int k = 0; k<models.size();k++)
            {
                if(click[0] == 0)
                    conversionBetween[k] = 0;
                else
                {
                   // System.out.println("4");
                    double var = (double) click[k]/(double) click[0] ;
                    if(var > 1)
                    {
                        conversionBetween[k] = (double) 1/ var;
                    }
                    else conversionBetween[k] = var;
                }
                //conversionBetween[k] = click[k]/click[0];
            }
            double [] advertise = new double[size2];
            double [] notadvertise = new double[size2];
            notadvertise[1] = 0;
            
            advertise[1] = conversionBetween[1];
            advertise[0] = Pxa1xn[1];
            notadvertise[0] = 1 - Pxa1xn[0] * advertise[0];
            for(int m = 2; m < size2 ; m++)
            {
                if(conversionBetween[m]== 0 ||Pxa1xn[m]==0 )
                {
                    notadvertise[m] = 1;
                    advertise[m] = 0;
                }
                else
                {
                    notadvertise[m] = (Math.round((conversionBetween[m] * advertise[0]/(Pxa1xn[m]*2))*1000.0)/1000.0) * (.4);
                    advertise[m] = ((conversionBetween[m] * advertise[0]) - (notadvertise[m]* Pxa1xn[m]))/Pxa1xn[m];
                }
            }
//            for(int k = 0; k<size2; k++)
//            {
//                System.out.println("Advertise "+ advertise[k]+" Not advertise "+notadvertise[k]+" P"+Pxa1xn[k]);
//            }
           // System.out.println("5");
            for(int index = 0;index < click.length;index++)
            {
                for(index2 = 0; index2 <click.length; index2++)
                {
                    if(click[index2] == 0)
                    a[index][index2] = 0;
                    else
                    {
                        double var = (double)click[index]/(double)click[index2];
                        if(var > 1)
                        a[index][index2]= (double)1 / var;
                        else 
                             a[index][index2]= var;
                    }
                }
            }
            double budgetPerItem = 0;
            for(int q = 0; q < size2; q++)
            {
                budgetPerItem += advertise[q];
            }
            budgetPerItem = Math.round(budgetPerItem*100.0)/100.0;
            
            double budgetReal = 0.75;
            double compatition = budgetPerUser/budgetPerItem;
            System.out.println("budgetPerItem" + budgetPerItem + "compati" + compatition);
            double[] policy = new double [size2];
            for(int p = 0; p<size2; p++)
            {
                //advertise[p] = advertise[p]*compatition;
                double mau = advertise[p]*compatition + notadvertise[p];
                if(mau == 0)
                    policy[p] = 0;
                else 
                {
                    
                    policy[p] = Math.round((advertise[p]*compatition/mau)*1000.0)/1000.0;
                }
                 //System.out.println("Policy per user "+policy[p]);  
            }
                     
            //double convertBudget = budgetPerItem
//            for(int o = 0; o < models.size();o++)
//            {
//                System.out.print("Pxa1xn "+Pxa1xn[o]+" ");
//                System.out.println();
//                System.out.print("conversionBetween "+conversionBetween[o]+" ");
//            }
//            for(int idex=0;idex<size;idex++)
//                 {
//                 for(int jdxex=0;jdxex<size;jdxex++)
//                    {
//                      
//                      System.out.print(a[idex][jdxex]+" ");
//                    }
//                  System.out.println();
//                  }
            int t = 0;
            System.out.println("numberOfKey" + numberOfKey);
            MarkovItem [] markovArray = new MarkovItem[size2];
            List<MarkovItem> Markovitem = new ArrayList<MarkovItem>();
            for(MDPModel item1: models)
            {
                    markovArray[t] = new MarkovItem(item1.getKeyword(), policy[t]);
                    //markovItem.add(new MarkovItem(item1.getKeyword(), policy[t]));
                     System.out.println("Khoa Ham"+markovArray[t].getOptimalPolicy());
                //}
                t++;
            }
           
            System.out.println("Pass 2");
            Arrays.sort(markovArray);
             for(int c = 0; c< size2; c++)
            {
                System.out.println("PAss 1"+markovArray[c].getKeyword() +markovArray[c].getOptimalPolicy());
            }
            //Collections.sort(models);
            for(int c = 0; c< numberOfKey; c++)
            {
                System.out.println("PAss 3"+markovArray[c].getOptimalPolicy());
            }
            for(int b = size2-1; b > size2-1 - numberOfKey ; b--)
            {
                markovItem.add(markovArray[b]);
            }
            //markovItem = bidDAO.getMarkovItem(numberOfKey);
            //Collections.sort(markovItem);
            //Collections.sort(markovItem);
            //Collections.sort(markovItem,Collections);
//            Collections.sort(markovItem, new Comparator<markovItem>(){
//                public double compareTo(MarkovItem o1, MarkovItem o2) {
//        return new Double (o1.getOptimalPolicy()).compareTo(o2.getOptimalPolicy());
//                }
//            for(MarkovItem item: markovItem)
//            {
//                System.out.println("ABC"+item.getOptimalPolicy());
//            }
//            count++;   
        reader.close();


        return SUCCESS;
    }

    /**
     * @return the markovItem
     */
    public List<MarkovItem> getMarkovItem() {
        return markovItem;
    }

    /**
     * @param markovItem the markovItem to set
     */
    public void setMarkovItem(List<MarkovItem> markovItem) {
        this.markovItem = markovItem;
    }
}